/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.fch.sdlibrary.security;

import com.fch.sdlibrary.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    UserService customUserDetailsService;

    @Autowired
    MyAuthenticationFailHandler myAuthenticationFailHandler;

    @Autowired
    MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    private final String[] PASS_PATH = {"/NeedLogin", "/QueryAllBookByPage", "/Register", "/img/**", "/login/**"};

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //设置 session 为无状态，因为基于 token 不需要 session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                //设置访问权限 
                .authorizeRequests()
                //.antMatchers("/home/**").hasAnyRole("admin","user") //admin和user 都有权访问
                //.antMatchers("/home/**").hasRole("admin") //admin和user 都有权访问
                .antMatchers("/Admin/**").hasRole("admin") //只有admin有权访问
                .antMatchers(PASS_PATH).permitAll() //只有admin有权访问
                .anyRequest().authenticated() //任何服务 登陆后才可以访问

                .and()
                .logout()
                .logoutUrl("/logout")
                //尚未登陆提示
                .and()
                .formLogin().loginPage("/NeedLogin")
                //security提供的登陆服务
                .loginProcessingUrl("/login") //参数 /login?username=xx&password=xx
                // 设置登陆成功url
                .defaultSuccessUrl("/").permitAll()
//                .successHandler(myAuthenticationSuccessHandler)
//                .failureHandler(myAuthenticationFailHandler)
                //开启跨域 cors()
                .and().cors().configurationSource(corsConfigurationSource())
                .and().csrf().disable()
                //登录拦截器 成功登录 发放token
//                //其他访问拦截器 验证token是否有效 有效才放行
                .addFilter(jwtLoginFilter())
                .addFilter(new JwtAuthenticationFilter(authenticationManager()));

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置用户User 根据用户名 找到用户User，比对密码 获取role
        auth.userDetailsService(customUserDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    private JwtLoginFilter jwtLoginFilter() throws Exception {
        JwtLoginFilter jwtLoginFilter = new JwtLoginFilter(authenticationManager());
        jwtLoginFilter.setAuthenticationSuccessHandler(myAuthenticationSuccessHandler);
        jwtLoginFilter.setAuthenticationFailureHandler(myAuthenticationFailHandler);
        return jwtLoginFilter;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //spring security 配置跨域访问资源
    private CorsConfigurationSource corsConfigurationSource() {
        CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOriginPattern("*"); //同源配置，*表示任何请求都视为同源，若需指定ip和端口可以改为如“localhost：8080”，多个以“，”分隔；
        corsConfiguration.addAllowedHeader("*");  //header，允许哪些header
        corsConfiguration.addAllowedMethod("*");  //允许的请求方法，PSOT、GET、PUT等
        corsConfiguration.addExposedHeader("token"); //拓展header 浏览器放过redponse的token 不然跨域登录收不到token
        corsConfiguration.setAllowCredentials(true); //允许浏览器携带cookie
        ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**", corsConfiguration); //配置允许跨域访问的url
        return source;
    }

}
